home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio / Ham Radio CD-ROM (Emerald Software) (1995).ISO / misc / 9q920411 / tcpsock.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-11  |  8.0 KB  |  364 lines

  1. #include "global.h"
  2. #include "tcp.h"
  3. #include "socket.h"
  4. #include "usock.h"
  5.  
  6. static void s_trcall __ARGS((struct tcb *tcb,int cnt));
  7. static void s_tscall __ARGS((struct tcb *tcb,int old,int new));
  8. static void s_ttcall __ARGS((struct tcb *tcb,int cnt));
  9. static void trdiscard __ARGS((struct tcb *tcb,int cnt));
  10. static void autobind __ARGS((struct usock *up));
  11.  
  12. int16 Lport = 1024;
  13.  
  14. int
  15. so_tcp(up,protocol)
  16. struct usock *up;
  17. int protocol;
  18. {
  19.     up->type = TYPE_TCP;
  20.     strcpy(up->eol,INET_EOL);
  21.     return 0;
  22. }
  23. int
  24. so_tcp_listen(up,backlog)
  25. struct usock *up;
  26. int backlog;
  27. {
  28.     int s;
  29.     struct sockaddr_in *local;
  30.     struct socket lsock;
  31.  
  32.     s = up - Usock + SOCKBASE;
  33.     if(up->name == NULLCHAR)
  34.         autobind(up);
  35.  
  36.     local = (struct sockaddr_in *)up->name;
  37.     lsock.address = local->sin_addr.s_addr;
  38.     lsock.port = local->sin_port;
  39.     up->cb.tcb = open_tcp(&lsock,NULLSOCK,
  40.      backlog ? TCP_SERVER:TCP_PASSIVE,0,
  41.     s_trcall,s_ttcall,s_tscall,up->tos,s);
  42.     return 0;
  43. }
  44. int
  45. so_tcp_conn(up)
  46. struct usock *up;
  47. {
  48.     int s;
  49.     struct tcb *tcb;
  50.     struct socket lsock,fsock;
  51.     struct sockaddr_in *local,*remote;
  52.  
  53.     if(up->name == NULLCHAR) {
  54.         autobind(up);
  55.     }
  56.     if(checkipaddr(up->peername,up->namelen) == -1){
  57.         errno = EAFNOSUPPORT;
  58.         return -1;
  59.     }
  60.     s = up - Usock + SOCKBASE;
  61.     /* Construct the TCP-style ports from the sockaddr structs */
  62.     local = (struct sockaddr_in *)up->name;
  63.     remote = (struct sockaddr_in *)up->peername;
  64.  
  65.     if(local->sin_addr.s_addr == INADDR_ANY)
  66.         /* Choose a local address */
  67.         local->sin_addr.s_addr = locaddr(remote->sin_addr.s_addr);
  68.  
  69.     lsock.address = local->sin_addr.s_addr;
  70.     lsock.port = local->sin_port;
  71.     fsock.address = remote->sin_addr.s_addr;
  72.     fsock.port = remote->sin_port;
  73.  
  74.     /* Open the TCB in active mode */
  75.     up->cb.tcb = open_tcp(&lsock,&fsock,TCP_ACTIVE,0,
  76.      s_trcall,s_ttcall,s_tscall,up->tos,s);
  77.  
  78.     /* Wait for the connection to complete */
  79.     while((tcb = up->cb.tcb) != NULLTCB && tcb->state != TCP_ESTABLISHED){
  80.         if(up->noblock){
  81.             errno = EWOULDBLOCK;
  82.             return -1;
  83.         } else if((errno = pwait(up)) != 0){
  84.             return -1;
  85.         }
  86.     }
  87.     if(tcb == NULLTCB){
  88.         /* Probably got refused */
  89.         free(up->peername);
  90.         up->peername = NULLCHAR;
  91.         errno = ECONNREFUSED;
  92.         return -1;
  93.     }
  94.     return 0;
  95. }
  96. int
  97. so_tcp_recv(up,bpp,from,fromlen)
  98. struct usock *up;
  99. struct mbuf **bpp;
  100. char *from;
  101. int *fromlen;
  102. {
  103.     int cnt;
  104.     struct tcb *tcb;
  105.  
  106.     while((tcb = up->cb.tcb) != NULLTCB && tcb->r_upcall != trdiscard
  107.      && (cnt = recv_tcp(tcb,bpp,(int16)0)) == -1){
  108.         if(up->noblock){
  109.             errno = EWOULDBLOCK;
  110.             return -1;
  111.         } else if((errno = pwait(up)) != 0){
  112.             return -1;
  113.         }
  114.     }
  115.     if(tcb == NULLTCB){
  116.         /* Connection went away */
  117.         errno = ENOTCONN;
  118.         return -1;
  119.     } else if(tcb->r_upcall == trdiscard){
  120.         /* Receive shutdown has been done */
  121.         errno = ENOTCONN;    /* CHANGE */
  122.         return -1;
  123.     }
  124.     return cnt;
  125. }
  126. int
  127. so_tcp_send(up,bp,to)
  128. struct usock *up;
  129. struct mbuf *bp;
  130. char *to;
  131. {
  132.     struct tcb *tcb;
  133.     int cnt;
  134.  
  135.     if((tcb = up->cb.tcb) == NULLTCB){
  136.         free_p(bp);
  137.         errno = ENOTCONN;
  138.         return -1;
  139.     }        
  140.     cnt = send_tcp(tcb,bp);
  141.  
  142.     while((tcb = up->cb.tcb) != NULLTCB &&
  143.      tcb->sndcnt > tcb->window){
  144.         /* Send queue is full */
  145.         if(up->noblock){
  146.             errno = EWOULDBLOCK;
  147.             return -1;
  148.         } else if((errno = pwait(up)) != 0){
  149.             return -1;
  150.         }
  151.     }
  152.     if(tcb == NULLTCB){
  153.         errno = ENOTCONN;
  154.         return -1;
  155.     }
  156.     return cnt;
  157. }
  158. int
  159. so_tcp_qlen(up,rtx)
  160. struct usock *up;
  161. int rtx;
  162. {
  163.     int len;
  164.  
  165.     switch(rtx){
  166.     case 0:
  167.         len = up->cb.tcb->rcvcnt + len_p(up->ibuf);
  168.         break;
  169.     case 1:
  170.         len = up->cb.tcb->sndcnt + len_p(up->obuf);
  171.         break;
  172.     }
  173.     return len;
  174. }
  175. int
  176. so_tcp_kick(up)
  177. struct usock *up;
  178. {
  179.     kick_tcp(up->cb.tcb);
  180.     return 0;
  181. }
  182. int
  183. so_tcp_shut(up,how)
  184. struct usock *up;
  185. int how;
  186. {
  187.     switch(how){
  188.     case 0:    /* No more receives -- replace upcall */
  189.         up->cb.tcb->r_upcall = trdiscard;
  190.         break;
  191.     case 1:    /* Send EOF */
  192.         close_tcp(up->cb.tcb);
  193.         break;
  194.     case 2:    /* Blow away TCB */
  195.         reset_tcp(up->cb.tcb);
  196.         up->cb.tcb = NULLTCB;
  197.         break;
  198.     }
  199.     return 0;
  200. }
  201. int
  202. so_tcp_close(up)
  203. struct usock *up;
  204. {
  205.     if(up->cb.tcb != NULLTCB){    /* In case it's been reset */
  206.         up->cb.tcb->r_upcall = trdiscard;
  207.         /* Tell the TCP_CLOSED upcall there's no more socket */
  208.         up->cb.tcb->user = -1;
  209.         close_tcp(up->cb.tcb);
  210.     }
  211.     return 0;
  212. }
  213. /* TCP receive upcall routine */
  214. static void
  215. s_trcall(tcb,cnt)
  216. struct tcb *tcb;
  217. int cnt;
  218. {
  219.     /* Wake up anybody waiting for data, and let them run */
  220.     psignal(itop(tcb->user),1);
  221.     pwait(NULL);
  222. }
  223. /* TCP transmit upcall routine */
  224. static void
  225. s_ttcall(tcb,cnt)
  226. struct tcb *tcb;
  227. int cnt;
  228. {
  229.     /* Wake up anybody waiting to send data, and let them run */
  230.     psignal(itop(tcb->user),1);
  231.     pwait(NULL);
  232. }
  233. /* TCP state change upcall routine */
  234. static void
  235. s_tscall(tcb,old,new)
  236. struct tcb *tcb;
  237. int old,new;
  238. {
  239.     int s,ns;
  240.     struct usock *up,*nup,*oup;
  241.     union sp sp;
  242.  
  243.     s = tcb->user;
  244.     oup = up = itop(s);
  245.  
  246.     switch(new){
  247.     case TCP_CLOSED:
  248.         /* Clean up. If the user has already closed the socket,
  249.          * then up will be null (s was set to -1 by the close routine).
  250.          * If not, then this is an abnormal close (e.g., a reset)
  251.          * and clearing out the pointer in the socket structure will
  252.          * prevent any further operations on what will be a freed
  253.          * control block. Also wake up anybody waiting on events
  254.          * related to this tcb so they will notice it disappearing.
  255.          */
  256.         if(up != NULLUSOCK){
  257.             up->cb.tcb = NULLTCB;
  258.             free_p(up->obuf);
  259.             up->obuf = NULLBUF;
  260.             free_p(up->ibuf);
  261.             up->ibuf = NULLBUF;
  262.             up->errcodes[0] = tcb->reason;
  263.             up->errcodes[1] = tcb->type;
  264.             up->errcodes[2] = tcb->code;
  265.         }
  266.         del_tcp(tcb);
  267.         break;
  268.     case TCP_SYN_RECEIVED:
  269.         /* Handle an incoming connection. If this is a server TCB,
  270.          * then we're being handed a "clone" TCB and we need to
  271.          * create a new socket structure for it. In either case,
  272.          * find out who we're talking to and wake up the guy waiting
  273.          * for the connection.
  274.          */
  275.         if(tcb->flags.clone){
  276.             /* Clone the socket */
  277.             ns = socket(AF_INET,SOCK_STREAM,0);
  278.             nup = itop(ns);
  279.             ASSIGN(*nup,*up);
  280.             tcb->user = ns;
  281.             nup->cb.tcb = tcb;
  282.             /* Allocate new memory for the name areas */
  283.             nup->name = mallocw(SOCKSIZE);
  284.             nup->peername = mallocw(SOCKSIZE);
  285.             /* Store the new socket # in the old one */
  286.             up->rdysock = ns;
  287.             up = nup;
  288.             s = ns;
  289.         } else {
  290.             /* Allocate space for the peer's name */
  291.             up->peername = mallocw(SOCKSIZE);
  292.             /* Store the old socket # in the old socket */
  293.             up->rdysock = s;
  294.         }
  295.         /* Load the addresses. Memory for the name has already
  296.          * been allocated, either above or in the original bind.
  297.          */
  298.         sp.p = up->name;
  299.         sp.in->sin_family = AF_INET;
  300.         sp.in->sin_addr.s_addr = up->cb.tcb->conn.local.address;
  301.         sp.in->sin_port = up->cb.tcb->conn.local.port;
  302.         up->namelen = SOCKSIZE;
  303.  
  304.         sp.p = up->peername;
  305.         sp.in->sin_family = AF_INET;
  306.         sp.in->sin_addr.s_addr = up->cb.tcb->conn.remote.address;
  307.         sp.in->sin_port = up->cb.tcb->conn.remote.port;
  308.         up->peernamelen = SOCKSIZE;
  309.  
  310.         /* Wake up the guy accepting it, and let him run */
  311.         psignal(oup,1);
  312.         pwait(NULL);
  313.         break;
  314.     default:    /* Ignore all other state transitions */
  315.         break;
  316.     }
  317.     psignal(up,0);    /* In case anybody's waiting */
  318. }
  319. /* Discard data received on a TCP connection. Used after a receive shutdown or
  320.  * close_s until the TCB disappears.
  321.  */
  322. static void
  323. trdiscard(tcb,cnt)
  324. struct tcb *tcb;
  325. int cnt;
  326. {
  327.     struct mbuf *bp;
  328.  
  329.     recv_tcp(tcb,&bp,(int16)cnt);
  330.     free_p(bp);
  331. }
  332.  
  333. /* Issue an automatic bind of a local address */
  334. static void
  335. autobind(up)
  336. struct usock *up;
  337. {
  338.     struct sockaddr_in local;
  339.     int s;
  340.  
  341.     s = up - Usock + SOCKBASE;
  342.     local.sin_family = AF_INET;
  343.     local.sin_addr.s_addr = INADDR_ANY;
  344.     local.sin_port = Lport++;
  345.     bind(s,(char *)&local,sizeof(struct sockaddr_in));
  346. }
  347. char *
  348. tcpstate(up)
  349. struct usock *up;
  350. {
  351.     if(up->cb.tcb == NULLTCB)
  352.         return NULLCHAR;
  353.     return Tcpstates[up->cb.tcb->state];
  354. }
  355. int
  356. so_tcp_stat(up)
  357. struct usock *up;
  358. {
  359.     st_tcp(up->cb.tcb);
  360.     return 0;
  361. }
  362.  
  363.  
  364.